Skip to main content

How Net Works

Net Protocol is a decentralized onchain messaging system that enables efficient storage and retrieval of messages across multiple dimensions. This technical overview explains the core mechanisms that make Net work.

Core Architecture

The Net Contract

Net Protocol is implemented as a single smart contract deployed at the same address across multiple EVM-compatible blockchains:

Contract Address: 0x00000000B24D62781dB359b07880a105cD0b64e6

The contract uses two main storage structures:

  • mapping(bytes32 hashVal => uint256[] messageIndexes) public hashToMessageIndexes - Multi-dimensional indexing
  • address[] public messagePointers - SSTORE2 pointers to message data

Message Structure

Every message follows this standardized structure:

struct Message {
address app; // Contract address that sent the message
address sender; // User address who sent the message
uint256 timestamp; // Block timestamp when message was sent
bytes data; // Binary data payload
string text; // Human-readable text content
string topic; // Message topic/category for indexing
}

Multi-Dimensional Indexing System

Net's key innovation is its indexing system that enables efficient querying across multiple dimensions simultaneously.

Index Types

The system creates five types of indexes for each message:

  1. App Index: keccak256(abi.encodePacked(app)) - All messages from a specific app
  2. App + User Index: keccak256(abi.encodePacked(app, user)) - User's messages in an app
  3. App + Topic Index: keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic)) - App messages by topic
  4. App + User + Topic Index: keccak256(abi.encodePacked(APP_USER_TOPIC_HASH_PREFIX, app, user, topic)) - User's messages in app by topic
  5. Global Index: Direct access via messagePointers array - All messages chronologically

Hash Prefixes

To prevent hash collisions between different index types, Net uses prefixes:

  • APP_TOPIC_HASH_PREFIX = 1
  • APP_USER_TOPIC_HASH_PREFIX = 2

Message Sending Process

Direct Messages (sendMessage)

When a user sends a direct message:

  1. Validation: Checks that message is not empty (lines 114-116 in Net.sol)
  2. Index Creation: Updates all four hash indexes with address(0) as app (lines 122-140)
  3. Storage: Encodes and stores message using SSTORE2 (lines 146-163)
  4. Event: Emits MessageSent event with message index (line 143)

App Messages (sendMessageViaApp)

When an app sends a message on behalf of a user:

  1. Validation: Checks that message is not empty (lines 44-46 in Net.sol)
  2. Index Creation: Updates all four hash indexes with the app address (lines 52-78)
  3. Storage: Encodes and stores message using SSTORE2 (lines 84-101)
  4. Event: Emits MessageSentViaApp event with message index (line 81)

Storage with SSTORE2

Net uses SSTORE2 for gas-efficient message storage:

// Each message is stored individually
messagePointers.push(
SSTORE2.write(
abi.encode(
msg.sender, // app
sender, // sender
block.timestamp, // timestamp
data, // data
text, // text
topic // topic
)
)
);

This approach provides gas efficiency for larger data while maintaining individual message accessibility.

Message Retrieval

Single Message Retrieval

Messages are retrieved by reading from SSTORE2 and decoding:

function getMessage(uint256 idx) external view returns (Message memory) {
return decodeMessageAtIndex(idx);
}

function decodeMessageAtIndex(uint256 idx) public view returns (Message memory) {
return decodeMessage(SSTORE2.read(messagePointers[idx]));
}

Multi-Dimensional Querying

The indexing system enables efficient queries across different dimensions:

  • By App: getMessageForApp(idx, app) - Get message from specific app
  • By App + User: getMessageForAppUser(idx, app, user) - Get user's message in app
  • By App + Topic: getMessageForAppTopic(idx, app, topic) - Get app message by topic
  • By App + User + Topic: getMessageForAppUserTopic(idx, app, user, topic) - Most specific query

Batch Retrieval

Range-based queries enable efficient batch operations:

  • getMessagesInRange(startIdx, endIdx) - Get multiple messages by global index range
  • getMessagesInRangeForApp(startIdx, endIdx, app) - Get multiple messages from app
  • Similar functions for all index types

Error Handling

Net implements four custom errors for robust error handling:

  • MsgEmpty() - Reverted when attempting to send empty messages
  • InvalidRange() - Reverted when start index >= end index
  • InvalidStartIndex() - Reverted when start index is out of bounds
  • InvalidEndIndex() - Reverted when end index is out of bounds

Cross-Chain Consistency

Net maintains the same contract address across all supported chains through CREATE2 deployment, enabling consistent cross-chain interactions and data portability.

Security Model

Permissionless Design

  • No Access Control: Anyone can send messages (lines 42, 108 in Net.sol)
  • No Censorship: Messages cannot be blocked or modified
  • Immutable Storage: Once stored, messages cannot be changed

This architecture enables Net to serve as a foundational protocol for building fully onchain applications that can efficiently store, index, and retrieve data across multiple dimensions while maintaining decentralization and censorship resistance.